package smetana.modules.ui.form.doc;

import com.google.inject.Inject;
import org.apache.pivot.collections.List;
import org.apache.pivot.collections.Sequence;
import org.apache.pivot.wtk.*;
import org.apache.pivot.wtkx.WTKX;
import smetana.domain.join.DocPositionReport;
import smetana.domain.raw.Doc;
import smetana.domain.raw.DocPosition;
import smetana.domain.raw.Position;
import smetana.modules.business.BusinessDoc;
import smetana.modules.business.BusinessDocPosition;
import smetana.modules.business.BusinessPivot;
import smetana.modules.business.BusinessPosition;
import smetana.modules.ui.form.AbstractPanel;
import smetana.modules.ui.model.*;
import smetana.modules.ui.model.Cursor;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * @author dmitry.mamonov
 */
public class ProductsCartPanel extends AbstractPanel {
    @Inject
    BusinessPivot businessPivot;

    @Inject
    BusinessPosition businessPosition;

    @Inject
    BusinessDoc businessDoc;

    @Inject
    BusinessDocPosition businessDocPosition;

    @WTKX
    TableView tableView;

    @WTKX
    PushButton buttonAdd;

    @WTKX
    PushButton buttonRemove;

    @WTKX
    Spinner fieldAmount;

    @WTKX
    TextInput fieldSummaryPrice;

    @Inject
    UIModel uiModel;

    @Inject
    CursorPosition cursorPosition;

    @Inject
    CursorDoc cursorDoc;

    DecimalFormat format = new DecimalFormat("#,##0.00р");

    Scope scope = Scope.UI;

    Action actionAdd = new Action() {
        @Override
        @SuppressWarnings("unchecked")
        public void perform() {
            Position position = cursorPosition.get();
            DocPosition docItem = businessDocPosition.newDocPosition(cursorDoc.get());
            docItem.setAmount(BigDecimal.ONE);
            docItem.setRealPrice(position.getPrice());
            docItem.setPositionId(position.getId());
            businessDocPosition.saveDocPosition(docItem);
            List<DocPositionReport> tableModel = (List<DocPositionReport>) tableView.getTableData();
            DocPositionReport docItemReport = businessDocPosition.findDocPositionReport(docItem.getId());
            tableModel.add(docItemReport);
            tableView.setSelectedIndex(tableModel.indexOf(docItemReport));
            tableView.validate();
            Bounds selectedRowBounds = tableView.getRowBounds(tableView.getSelectedIndex());
            selectedRowBounds.translate(0, selectedRowBounds.height); //TODO: is it bug in pivot?
            tableView.scrollAreaToVisible(selectedRowBounds);
        }
    };

    Action actionRemove = new Action() {
        @Override
        @SuppressWarnings("unchecked")
        public void perform() {
            DocPositionReport docItemReport = (DocPositionReport) tableView.getSelectedRow();
            businessDocPosition.deleteDocPosition(docItemReport);
            List<DocPositionReport> tableModel = (List<DocPositionReport>) tableView.getTableData();
            tableModel.remove(docItemReport);
            updateTotals();
        }
    };

    public ProductsCartPanel() {
        super();
    }

    @Override
    public void init() {
        wtkx.bind(this);
        buttonAdd.setAction(actionAdd);
        buttonRemove.setAction(actionRemove);
        cursorPosition.getConsumers().add(new smetana.modules.ui.model.Cursor.Consumer<Position>() {
            @Override
            public void onCurrentSwitched(Cursor<Position> positionCursor) {
                updateActionsAndFieldsStatus();
            }
        });

        cursorDoc.getConsumers().add(new Cursor.Consumer<Doc>() {
            @Override
            public void onCurrentSwitched(Cursor<Doc> cursor) {
                tableView.setTableData(businessPivot.pivotListOfDocPositionReports(cursor.get()));
                updateActionsAndFieldsStatus();
            }
        });

        tableView.getTableViewSelectionListeners().add(new TableViewSelectionListener.Adapter() {
            @Override
            public void selectedRangesChanged(TableView tableView, Sequence<Span> previousSelectedRanges) {
                updateActionsAndFieldsStatus();
            }
        });
        fieldAmount.getSpinnerSelectionListeners().add(new UIScopeSpinnerSelectionListener() {
            @Override
            @SuppressWarnings("unchecked")
            protected void selectedIndexChangedInUIScope(Spinner spinner, int previousSelectedIndex) {
                int index = tableView.getSelectedIndex();
                DocPositionReport docItem = (DocPositionReport) tableView.getSelectedRow();
                docItem.setAmount(new BigDecimal((Integer) spinner.getSelectedItem()));
                businessDocPosition.saveDocPosition(docItem);
                docItem = businessDocPosition.findDocPositionReport(docItem.getId());
                List<DocPositionReport> tableModelRef = (List<DocPositionReport>) tableView.getTableData();
                tableModelRef.update(index, docItem);
                updateTotals();
            }
        });
        updateActionsAndFieldsStatus();

    }

    private void updateActionsAndFieldsStatus() {
        runInCodeScope(new Runnable() {
            @Override
            public void run() {
                actionAdd.setEnabled(cursorPosition.hasValue());
                actionRemove.setEnabled(tableView.getSelectedRow() != null);

                if (tableView.getSelectedIndex() >= 0) {
                    DocPositionReport dir = (DocPositionReport) tableView.getSelectedRow();
                    int fieldAmountValue = dir.getAmount().intValue();
                    fieldAmount.setSelectedItem(fieldAmountValue);
                    fieldAmount.setEnabled(true);
                } else {
                    fieldAmount.setSelectedItem(0);
                    fieldAmount.setEnabled(false);
                }
                updateTotals();
            }
        });
    }

    @SuppressWarnings("unchecked")
    protected void updateTotals() {
        double summ = 0.0D;
        for (DocPositionReport row : (List<DocPositionReport>) tableView.getTableData()) {
            summ += row.getTotalPrice().doubleValue();
        }
        fieldSummaryPrice.setText(format.format(summ));
    }

    private void runInCodeScope(Runnable command) {
        Scope backup = scope;
        try {
            scope = Scope.Code;
            command.run();
        } finally {
            scope = backup;
        }
    }

    enum Scope {
        Code, UI
    }

    private abstract class UIScopeSpinnerSelectionListener implements SpinnerSelectionListener {
        @Override
        public final void selectedIndexChanged(Spinner spinner, int previousSelectedIndex) {
            if (scope == Scope.UI) {
                selectedIndexChangedInUIScope(spinner, previousSelectedIndex);
            }
        }

        protected abstract void selectedIndexChangedInUIScope(Spinner spinner, int previousSelectedIndex);
    }
}
